package com.ym.medical.service.impl;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.thread.GlobalThreadPool;
import cn.hutool.extra.spring.SpringUtil;
import com.ym.common.annotations.EnumDescription;
import com.ym.common.constant.Constants;
import com.ym.common.constant.DictEnum;
import com.ym.core.redis.RedisKeyUtil;
import com.ym.core.utils.tkmybatis.BaseSVImpl;
import com.ym.medical.dao.DoctorPhoneSettingDao;
import com.ym.medical.dao.SysDictDao;
import com.ym.medical.domain.entity.DoctorPhoneSettingEntity;
import com.ym.medical.domain.entity.SysDictEntity;
import com.ym.medical.domain.param.SysDictQueryParam;
import com.ym.medical.domain.param.SysDictUpdateParam;
import com.ym.medical.domain.vo.PhoneAppointmentTimeVo;
import com.ym.medical.domain.vo.SysDictListPcVO;
import com.ym.medical.enums.DividedRateEnum;
import com.ym.medical.service.ISysDictSV;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字典Service业务层处理
 *
 * @author ym
 * @date 2020-08-17
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class SysDictSVImpl extends BaseSVImpl<SysDictEntity, SysDictDao> implements ISysDictSV, ApplicationRunner {

	@Value("${config-center.enums.scanBasePackages:null}")
	private String dictScanPackage;

	@Value("${config-center.enums.scan:false}")
	private boolean scan;


	@Autowired
	private DoctorPhoneSettingDao doctorPhoneSettingDao;


	@Override
	public void run(ApplicationArguments args) throws Exception {
		// 刷新枚举字典
		refreshEnumDictData();

	}

	/**
	 * 刷新枚举字典
	 */
	public void refreshEnumDictData() {
		if (!scan) {
			return;
		}
		GlobalThreadPool.execute(() -> {
			List<Class<DictEnum>> definitionEnum = loadDictEnum();
			log.info("刷新枚举字典....");
			SysDictEntity update = null;
			for (Class<DictEnum> DictEnumClass : definitionEnum) {
				try {
					// 0.基础数据构造
					DictEnum[] anEnums = DictEnumClass.getEnumConstants();
					EnumDescription annotation = DictEnumClass.getAnnotation(EnumDescription.class);
					String dictName = annotation.value();
					String dictCode = DictEnumClass.getSimpleName();
					// 1.字典数据构建
					for (int dictSort = 1; dictSort < anEnums.length + 1; dictSort++) {
						log.info("刷新......");
						String itemCode = anEnums[dictSort - 1].getKey();
						String itemName = anEnums[dictSort - 1].getValue();
						update = new SysDictEntity();
						update.setDictName(dictName);
						update.setDictCode(dictCode);
						update.setItemName(itemName);
						update.setItemCode(itemCode);
						update.setItemOrder((long) dictSort);
						update.setItemState("01");
						update.setCreatetime(new Date());
						update.setCreater(1L);
						// 1.查询是否存在
						boolean exist = this.exist(SelectWhere()
								.andEqualTo(SysDictEntity::getDictCode, dictCode)
								.andEqualTo(SysDictEntity::getItemCode, itemCode)
								.end()
						);
						if (!exist) {
							// 2新增字典数据
							this.insert(update);
						}
					}
				} catch (Exception e) {
					log.error(cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage(e));
				}
			}
			log.info("刷新枚举字典....完毕");
		});
	}

	/**
	 * 获取定义的字典类
	 *
	 * @return
	 */
	private List<Class<DictEnum>> loadDictEnum() {
		String DEFAULT_RESOURCE_PATTERN = "**/*.class";
		List<Class<DictEnum>> definitionEnum = new ArrayList<>();
		ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
		MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
		try {
			for (String aliasesPackage : dictScanPackage.split(",")) {
				String classPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
						+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
				Resource[] resources = resolver.getResources(classPath);
				if (resources != null && resources.length > 0) {
					MetadataReader metadataReader = null;
					for (Resource resource : resources) {
						if (resource.isReadable()) {
							metadataReader = metadataReaderFactory.getMetadataReader(resource);
							Class aClass = Class.forName(metadataReader.getClassMetadata().getClassName());
							if (aClass.getInterfaces().length > 0 && aClass.getInterfaces()[0].equals(DictEnum.class)) {
								Class<DictEnum> DictEnumClass = (Class<DictEnum>) aClass;
								definitionEnum.add(DictEnumClass);
							}
						}
					}
				}
			}
		} catch (Exception e) {
			log.error(ExceptionUtil.getRootCauseMessage(e));
		}
		return definitionEnum;
	}

	/**
	 * 查询字典列表
	 *
	 * @param queryParam 字典 查询参数
	 * @return 字典
	 */
	@Override
	public List<SysDictListPcVO> selectListPC(SysDictQueryParam queryParam) {
		List<SysDictListPcVO> sysDicts = mapper.selectListPC(queryParam);
		return sysDicts;
	}

	/**
	 * 新增字典
	 *
	 * @param updateParam 字典 新增参数
	 * @return 结果
	 */
	@Override
	public Long insertPC(SysDictUpdateParam updateParam) {
		SysDictEntity entity = updateParam.covert();
		this.insert(entity);
		return entity.getId();
	}

	/**
	 * 修改字典
	 *
	 * @param updateParam 字典 修改参数
	 * @return 结果
	 */
	@Override
	public int updateByIdPC(SysDictUpdateParam updateParam) {
		SysDictEntity entity = updateParam.covert();
		int result = this.updateById(entity);
		return result;
	}

	@Override
	@Cacheable(value = RedisKeyUtil.KEY_PREFIX + ":" + Constants.System.CACHE_DICT, key = "#dictCode+':'+'Single'+':'+#itemCode", unless = "#result == null ")
	public String getDictValue(String dictCode, String itemCode) {
		SysDictEntity itemName = mapper.selectOneByExample(Select().column("itemName")
				.where()
				.andEqualTo(SysDictEntity::getDictCode, dictCode)
				.andEqualTo(SysDictEntity::getItemCode, itemCode)
				.end());
		return itemName == null ? "" : itemName.getItemName();
	}

	@Override
	public String getDictValue(Class<? extends DictEnum> dictCode, DictEnum itemCode) {
		// 这样调用，为了走spring代理缓存
		return SpringUtil.getBean(ISysDictSV.class).getDictValue(dictCode, itemCode.getKey());
	}

	@Override
	public String getDictValue(Class<? extends DictEnum> dictCode, String itemCode) {
		// 这样调用，为了走spring代理缓存
		return SpringUtil.getBean(ISysDictSV.class).getDictValue(dictCode.getSimpleName(), itemCode);
	}

	@Override
	@Cacheable(value = RedisKeyUtil.KEY_PREFIX + ":" + Constants.System.CACHE_DICT, key = "#dictCode+':'+'List'+':ALL'", unless = "#result == null ")
	public List<SysDictEntity> getDictValues(String dictCode) {
		List<SysDictEntity> dictValues = mapper.selectByExample(
				Select().column("itemCode", "itemName")
						.where()
						.andEqualTo(SysDictEntity::getDictCode, dictCode)
						.end()
		);
		return dictValues;
	}

	@Override
	public Map<String, String> getDictValuesToMap(String dictCode) {
		// 这样调用，为了走spring代理缓存
		List<SysDictEntity> dictValues = SpringUtil.getBean(ISysDictSV.class).getDictValues(dictCode);
		return dictValues.stream().collect(Collectors.toMap(SysDictEntity::getItemCode, SysDictEntity::getItemName));
	}


	/***
	 * 医生预约时间表字典查询
	 * @return
	 */
	@Override
	public List<SysDictEntity> getTimeTable(Long serviceId) {
		List<SysDictEntity> timeTable = mapper.getTimeTable();
		if (null == serviceId) {
			return timeTable;
		}
		//查询医生设置的预约的时间
		List<PhoneAppointmentTimeVo> phoneSettingList =
				doctorPhoneSettingDao.getPhoneSets(serviceId);
		if (phoneSettingList.isEmpty()) {
			return timeTable;
		}
		for (SysDictEntity sysDict : timeTable) {
			for (DoctorPhoneSettingEntity phoneSetting : phoneSettingList) {
				boolean flag = sysDict.getItemName().equals(phoneSetting.getDpsWeek()) &&
						sysDict.getItemCode().equals(phoneSetting.getFlag());
				if (flag) {
					sysDict.setItemState("true");
					sysDict.setId(phoneSetting.getId());
				}
			}
		}
		return timeTable;
	}

	@Override
	public List<SysDictEntity> getDictValues(Class<? extends DictEnum> dictEnum) {
		return SpringUtil.getBean(ISysDictSV.class).getDictValues(dictEnum.getSimpleName());
	}

	@Override
	public Map<String, String> getDictValuesToMap(Class<? extends DictEnum> dictEnum) {
		return getDictValuesToMap(dictEnum.getSimpleName());
	}

	/**
	 * 数据字典省份查询
	 *
	 * @return
	 */
	@Override
	@Cacheable(value = RedisKeyUtil.KEY_PREFIX + ":" + Constants.System.CACHE_DICT, key = "'ProvData'+':'+'ALL'+':'+#itemCode+'-'+#itemLevel", unless = "#result == null ")
	public List<SysDictEntity> selectDictProv() {
		List<SysDictEntity> sysDicts = mapper.selectDictProv();
		return sysDicts;
	}

	@Override
	public List<SysDictEntity> getCodeAndDesc(Class<DividedRateEnum> dictCode) {
		return this.selectList(Select().column("item_code,item_desc")
				.where().andEqualTo(SysDictEntity::getDictCode, dictCode.getSimpleName()).end());
	}

	/**
	 * @param itemLevel 级别
	 * @param itemCode  上级code编码
	 * @return
	 */
	@Override
	@Cacheable(value = RedisKeyUtil.KEY_PREFIX + ":" + Constants.System.CACHE_DICT, key = "'ProvData'+':'+'SPLIT'+':'+#itemCode+'-'+#itemLevel", unless = "#result == null ")
	public List<SysDictEntity> selectByLevelAndCode(int itemLevel, String itemCode) {
		List<SysDictEntity> sysDicts = mapper.selectByLevelAndCode(itemLevel, itemCode);
		return sysDicts;
	}
}
